package work.display
{
	
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	
	import work.data.crypto.CryptoType;
	
	import zf.data.crypto.MD5;
	import zf.data.crypto.XXTEA;
	import zf.data.crypto.XXTEAAsyn;
	import zf.data.crypto.XXTEAAsynEvent;
	
	/**
	 * 加载完成事件 
	 * @eventType flash.events.Event.COMPLETE
	 */
	[Bindable]
	[Event(name="complete", type="flash.events.Event")]
	
	/**
	 * 加载进程事件,此加载过程会有多个层面,所以得到的百分比并不真实 
	 * @eventType flash.events.ProgressEvent.PROGRESS
	 */
	[Bindable]
	[Event(name="progress", type="flash.events.ProgressEvent")]
	
	/**
	 * 错误事件 
	 * @eventType flash.events.ErrorEvent.ERROR
	 */
	[Bindable]
	[Event(name="error", type="flash.events.ErrorEvent")]
	
	public class LoadEFC extends EventDispatcher
	{
		
		private var _url:String;
		private var _key:ByteArray;
		private var _contentData:ByteArray;
		
		
		public function LoadEFC()
		{
			
		}

		public function get contentData():ByteArray
		{
			return _contentData;
		}

		

		public function get url():String
		{
			return _url;
		}

		public function set url(value:String):void
		{
			_url = value;
		}

		public function get key():ByteArray
		{
			return _key;
		}

		public function set key(value:ByteArray):void
		{
			_key=value;
		}

		/**
		 * 将一个字符密匙转化为EFC文件可用密匙 
		 * @param key 字符串
		 * @return ByteArray
		 * 
		 */
		public static function toEFCKey(key:String):ByteArray
		{
			var byte:ByteArray=new ByteArray();
			byte.writeUTF(MD5.hash(key));
			return byte;
		}
		
		/**
		 * 加载 
		 * @param uri 地址
		 * @param key 密匙,EFC文件所使用的密匙为特殊密匙,请使用 LoadEFC.toEFCKey 函数转换您的密匙
		 * @see toEFCKey
		 */
		public function load(uri:String=null,key:ByteArray=null):void
		{
			if(uri)
			{
				_url=uri;
			}
			if(key)
			{
				_key=key;
			}			
			
			var urlLoad:URLLoader=new URLLoader();
			urlLoad.dataFormat=URLLoaderDataFormat.BINARY;
			urlLoad.addEventListener(Event.COMPLETE,onUrlLoadCompleteEvent);
			urlLoad.addEventListener(IOErrorEvent.IO_ERROR,onErrorEvent);
			urlLoad.addEventListener(ProgressEvent.PROGRESS,onPressEvent);
			urlLoad.load(new URLRequest(_url));
		}	
		
		private function onUrlLoadCompleteEvent(e:Event):void
		{
			var urlLoad:URLLoader=URLLoader(e.target);
			_contentData=urlLoad.data;
			urlLoad.removeEventListener(Event.COMPLETE,onUrlLoadCompleteEvent);
			urlLoad.removeEventListener(IOErrorEvent.IO_ERROR,onErrorEvent);
			urlLoad.removeEventListener(ProgressEvent.PROGRESS,onPressEvent);
			decrypt();
		}
		
		protected function onErrorEvent(e:ErrorEvent):void
		{
			//trace(e);
			//this.dispatchEvent(e);
			this.dispatchEvent(new ErrorEvent(e.type,e.bubbles,e.cancelable,e.text,e.errorID));
		}
		protected function onPressEvent(e:ProgressEvent):void
		{
			//this.dispatchEvent(new ProgressEvent(e.type,e.bubbles,e.cancelable,e.bytesLoaded,e.bytesTotal));
			this.dispatchEvent(e);
		}
		
		private function decrypt():void
		{
			_contentData.position=0;
			var code:uint=_contentData.readUnsignedInt();
			var fileName:String=_contentData.readUTF();
			/*var arr:Array=fileName.split(".");
			var fileType:String=arr.pop();
			trace(fileType);
			if(fileType.toLocaleLowerCase()!="efc")
			{
				throw new Error("不是EFC文件");
			}*/
			var byte:ByteArray=new ByteArray();
			byte.writeBytes(_contentData,_contentData.position,_contentData.bytesAvailable);
			_contentData.clear();
			
			_contentData=byte;
			try
			{
				if(code==0)
				{
					var xxtea:XXTEAAsyn=new XXTEAAsyn(_key);
					xxtea.addEventListener(XXTEAAsynEvent.PROGRESS,onXxteaHander);
					xxtea.addEventListener(XXTEAAsynEvent.DECRYPT_COMPLETE,onXxteaHander);
					xxtea.decryptAsyn(_contentData);
				}else if(code==1)
				{
					_contentData=XXTEA.decrypt(_contentData,_key);
					loadContent();
				}else
				{
					throw new Error("code is error!");
				}
			}catch(e:Error)
			{
				//trace(e);
				this.dispatchEvent(new ErrorEvent(ErrorEvent.ERROR,false,false,e.message,e.errorID));
			}
		}
		private function onXxteaHander(e:XXTEAAsynEvent):void
		{
			switch(e.type)
			{
				case XXTEAAsynEvent.DECRYPT_COMPLETE:
					_contentData=e.data;
					var xxtea:XXTEAAsyn=XXTEAAsyn(e.target);
					xxtea.removeEventListener(XXTEAAsynEvent.PROGRESS,onXxteaHander);
					xxtea.removeEventListener(XXTEAAsynEvent.DECRYPT_COMPLETE,onXxteaHander);
					loadContent();
					break;
				case XXTEAAsynEvent.PROGRESS:
					this.dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS,false,false,((e.state+1)*e.bytesLoaded),((e.bytesTotal+1)*e.totalState)));
					break;
			}
		}
		
		protected function loadContent():void
		{
			this.dispatchEvent(new Event(Event.COMPLETE));			
		}
		
	}
}